﻿using System;
using System.Threading;

namespace AjaxControlToolkit.LongOperations
{
    class WorkRequest : IWorkRequest
    {
        internal const int PENDING = 0;
        internal const int PROCESSED = 1;
        internal const int CANCELLED = 2;
        public readonly Guid WorkRequestID = Guid.NewGuid();

        public WorkRequest(WorkRequestDelegate cb, object arg,
                           bool propogateThreadPrincipal, bool propogateCallContext,
                           bool propogateHttpContext, bool propogateCASMarkers)
        {
            targetProc = cb;
            procArg = arg;
            procArgs = null;

            Initialize(propogateThreadPrincipal, propogateCallContext, propogateHttpContext, propogateCASMarkers);
        }

        public WorkRequest(Delegate cb, object[] args,
                            bool propogateThreadPrincipal, bool propogateCallContext,
                            bool propogateHttpContext, bool propogateCASMarkers)
        {
            targetProc = cb;
            procArg = null;
            procArgs = args;

            Initialize(propogateThreadPrincipal, propogateCallContext,
                        propogateHttpContext, propogateCASMarkers);
        }

        void Initialize(bool propogateThreadPrincipal, bool propogateCallContext,
                         bool propogateHttpContext, bool propogateCASMarkers)
        {
            workingTime = timeStampStarted = DateTime.Now;
            threadInfo = ThreadInfo.Capture(propogateThreadPrincipal, propogateCallContext,
                                             propogateHttpContext, propogateCASMarkers);
        }

        public string GetResult()
        {
            return string.Empty;
        }

        public bool Cancel()
        {
            // If the work request was pending, mark it cancelled.  Otherwise,
            // this method was called too late.  Note that this call can
            // cancel an operation without any race conditions.  But if the
            // result of this test-and-set indicates the request is in the
            // "processed" state, it might actually be about to be processed.
            //
            return (Interlocked.CompareExchange(ref state, CANCELLED, PENDING) == PENDING);
        }

        internal Delegate targetProc;         // Function to call.
        internal object procArg;            // State to pass to function.
        internal object[] procArgs;           // Used with Delegate.DynamicInvoke.
        internal DateTime timeStampStarted;   // Time work request was originally enqueued (held constant).
        internal DateTime workingTime;        // Current timestamp used for triggering new threads (moving target).
        internal ThreadInfo threadInfo;         // Everything we know about a thread.
        internal int state = PENDING;    // The state of this particular request.
    }
}
